<?php

define("PANDA_SUCCESS",           0);
define('PANDA_ERR_NULL',          -2);
define("PANDA_ERR_SYSTEM",        -1);
define('PANDA_ERR_ARGS',          -3);

define('PANDA_MEM_SET',           1);
define('PANDA_MEM_GET',           2);
define('PANDA_MEM_INCR',          3);
define('PANDA_MEM_DECR',          4);
define('PANDA_MEM_DELETE',        5);
define('PANDA_DB_SET',            6);
define('PANDA_DB_GET',            7);
define('PANDA_DB_INCR',           8);
define('PANDA_DB_DECR',           9);
define('PANDA_DB_DELETE',         10);


function panda_getErrMsg($ierr)
{
	switch($ierr)
	{
		case PANDA_SUCCESS:       return "Success";
		case PANDA_ERR_NULL:      return "Key is not exist";
		case PANDA_ERR_SYSTEM:    return "System error";
		case PANDA_ERR_ARGS:      return "input args is error";
		default:                  return "Undefined error";
	}
}

class Panda{
	var $sock;
	function __construct($port = 7080 ){
		$this->sock = pfsockopen("localhost", $port, $errno, $errstr);
		if (!$this->sock) {
			error_log("ERROR: $errno - $errstr");
                        exit;
                }
	} 

	function __destruct() {
	} 

	function set($hash, $expire, $kv, $method = PANDA_MEM_SET){
		$counts = sizeof($kv);
		if($counts == 0)
			return false;
		$input = pack("IIII", $method, $hash, 1*$expire, $counts);
		foreach($kv as $k=>$v)
			if(!empty($k))
				$input .=pack("I", strlen($k)).$k.pack("I",strlen($v)).$v;
	        var_dump($input);	
                fwrite($this->sock, $input);
	}

	function delete($hash, $kv, $method = PANDA_MEM_DELETE){
		$counts = sizeof($kv);
		if($counts == 0)
			return false;
		$input = pack("III", $method, $hash, $counts);
		foreach($kv as $k=>$v)
			if(!empty($k))
				$input .=pack("I", strlen($k)).$k;
	        var_dump($input);	
                fwrite($this->sock, $input);
	}


	function get($hash, $kv, $method= PANDA_MEM_GET){
		$arr = array();
		$counts = sizeof($kv);
		if($counts == 0)
			return false;

		$input = pack("III", $method, $hash, $counts);
		foreach($kv as $k=>$v){
			if(!empty($k))
				$input .=pack("I", strlen($k)).$k;
		}
		fwrite($this->sock, $input);

		$readlen = $READ = 1024;
		$response = fread($this->sock, $READ);
		// var_dump($response);
		if(isset($response{7}))
		{
			$sub = substr($response, 0, 8);
			$unpacked = unpack('I2',$sub);         
			//echo "yes:";  var_dump($unpacked); 
			if(isset($unpacked['1']) && isset($unpacked['2']))
			{
				if($unpacked['2'] != 0)
					return $unpacked['2']; // $arr;

				while( $unpacked['1'] > $readlen) 
				{    
				//	echo "not end, continue to read\n"; 
					$response .= fread($this->sock, $READ);
					$readlen += $READ;
				} 
			//	echo "read = "; var_dump($response);

				$idx = 8;
				$sub = substr($response, $idx , 4);
				$unpacked = unpack('I',$sub);      
			//	echo "items = "; var_dump($unpacked);
				$idx += 4;    
				$item = $unpacked['1'];
				for($j = 0; $j<$item ; $j++)
				{
					$str = substr($response, $idx, 4);
					$unpacked = unpack('Iint', $str);
					$idx += 4;
					$key = substr($response, $idx, $unpacked['int']);
			//		echo "key=$key\n";var_dump($unpacked);
					$idx += $unpacked['int'];
					$str = substr($response, $idx, 4);
					$unpacked = unpack('Iint', $str);
					$idx += 4;
					$val = substr($response, $idx, $unpacked['int']);
			//		echo "val =$val"; var_dump($unpacked);
					$idx += $unpacked['int'];
					$arr[$key] = $val;
				}
			}
		}
                else
                   echo "return error! : length = ".strlen($response);
            return $arr;                
	}

	function incr($hash, $key, $val, $method = PANDA_MEM_INCR){
		$input = pack("II", $method, $hash).pack("I", strlen($key)).$key.pack("l",1*$val);
		fwrite($this->sock, $input);

		$readlen = $READ = 1024;
		$response = fread($this->sock, $READ);
		var_dump($response);
		if(isset($response{7}))
		{
			$sub = substr($response, 0, 8);
			$unpacked = unpack('I2',$sub);         
			echo "yes:";  var_dump($unpacked); 
			if(isset($unpacked['1']) && isset($unpacked['2']))
			{
				if($unpacked['2'] != 0)
                                {
                                        echo $unpacked['2']."\n";
					return  false;
                                }
				$idx = 8;
				$sub = substr($response, $idx , $unpacked['1'] - $idx);
				$unpacked = unpack('I',$sub);      
			//	echo "items = "; var_dump($unpacked);
				return  $unpacked['1'];
			}
		}
		return false;              
	}

	function decr($hash, $key, $val, $method = PANDA_MEM_DECR ){
		$input = pack("II", $method, $hash).pack("I", strlen($key)).$key.pack("l",1*$val);
		fwrite($this->sock, $input);

		$readlen = $READ = 1024;
		$response = fread($this->sock, $READ);
		//var_dump($response);
		if(isset($response{7}))
		{
			$sub = substr($response, 0, 8);
			$unpacked = unpack('I2',$sub);         
		//	echo "yes:";  var_dump($unpacked); 
			if(isset($unpacked['1']) && isset($unpacked['2']))
			{
				if($unpacked['2'] != 0)
                                {
                                        echo $unpacked['2']."\n";
					return false;
                                }
				$idx = 8;
				$sub = substr($response, $idx , $unpacked['1'] - $idx);
				$unpacked = unpack('I',$sub);      
				//echo "items = "; var_dump($unpacked);
				return  $unpacked['1'];
			}
		}
		return false;              
	}

	function db_set($hash, $expire, $kv){
             return  $this->set($hash, $expire, $kv, PANDA_DB_SET);
	}

	function db_delete($hash, $kv){
                return $this->delete($hash, $kv, PANDA_DB_DELETE);
	}

	function db_get($hash, $kv){
		return $this->get($hash, $kv, PANDA_DB_GET);
	}

	function db_incr($hash, $key, $val){
		return $this->incr($hash, $key, $val, PANDA_DB_INCR);
	}

	function db_decr($hash, $key, $val ){
		return $this->decr($hash, $key, $val, PANDA_DB_DECR);
	}
}


function test_set($counts)
{
	$obj = new Panda();
        $arr = array();
        for($i=1; $i<= $counts; $i++)
           $arr["$i"] = "$i";
	$obj->set(0,0, $arr );
}

function test_db_set($counts)
{
	$obj = new Panda();
        $arr = array();
        for($i=1; $i<= $counts; $i++)
           $arr["$i"] = "$i";
	$obj->db_set(0,0, $arr );
}

function test_db_get($counts)
{
	$obj = new Panda();
	$arr = array();
	for($i=1; $i<= $counts; $i++)
		$arr["$i"] = "";
	$ret = $obj->db_get(0,$arr );
	var_dump($ret);
}


function test_get($counts)
{
	list($start_usec, $start_sec) = explode(" ", microtime());
	$start_time = ((float) $start_usec + (float) $start_sec);
	for($j=0; $j< 10000; $j++)
	{
		$obj = new Panda();
		$arr = array();
		for($i=1; $i<= $counts; $i++)
			$arr["$i"] = "";
		$ret = $obj->get(0,$arr );
		//var_dump($ret);
	}
	list($end_usec, $end_sec) = explode(" ", microtime());
	$end_time = ((float) $end_usec + (float) $end_sec);

	$total_time = $end_time - $start_time;
	echo "\n".$total_time."\n";
	echo 10000/$total_time;
	// var_dump($ret);
}

function test_pget($counts)
{
	$obj = new Panda();
        $arr = array();
        for($i=1; $i<= $counts; $i++)
           $arr["$i"] = "";

list($start_usec, $start_sec) = explode(" ", microtime());
$start_time = ((float) $start_usec + (float) $start_sec);
for($i=0; $i< 10000; $i++)
{
        $ret = $obj->get(0,$arr );
//var_dump($ret);
}
list($end_usec, $end_sec) = explode(" ", microtime());
$end_time = ((float) $end_usec + (float) $end_sec);

$total_time = $end_time - $start_time;
echo "\n".$total_time."\n";
echo 10000/$total_time;
       // var_dump($ret);
}


function test_incr($key, $val)
{
	$obj = new Panda();
        $arr = array();
        $ret = $obj->incr(0, "$key", $val);
        var_dump($ret);
}

function test_decr($key, $val)
{
	$obj = new Panda();
        $arr = array();
        $ret = $obj->decr(0, "$key", $val);
        var_dump($ret);
}

function test_delete($counts)
{
	$obj = new Panda();
        $arr = array();
        for($i=1; $i<= $counts; $i++)
           $arr["$i"] = "$i";
        $obj->delete(0, $arr);
}


//test_set(3);
//$ret = test_get(3);
/*
test_set(3);
$ret = test_get(3);
test_delete(3);
$ret = test_get(3);
*/
/*
test_set(3);
echo test_incr("3", 10);
echo "\n";
echo test_decr("3", 8);
*/

test_db_set(3);
echo "\n";
test_db_get(3);

?>
